

package com.lemon.cloud.log.aspect;

import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.servlet.JakartaServletUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HttpUtil;
import com.lemon.cloud.comm.constants.enums.LogBusType;
import com.lemon.cloud.core.utils.SpringContextHolder;
import com.lemon.cloud.log.entity.Log;
import com.lemon.cloud.log.event.SysLogEvent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * 操作日志使用spring event异步入库
 *
 * @author L.cm
 */
@Aspect
@Slf4j
@Component
public class SysLogAspect {

    @Value("${spring.application.name:0}")
    private String serviceId;

    @Around("@annotation(sysLog)")
    @SneakyThrows
    public Object around(ProceedingJoinPoint point, com.lemon.cloud.log.annotation.SysLog sysLog) {
        String strClassName = point.getTarget().getClass().getName();
        String strMethodName = point.getSignature().getName();
        log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);

        String title = sysLog.value();
        LogBusType logBusType = sysLog.businessType();

        HttpServletRequest request = ((ServletRequestAttributes) Objects
                .requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        Log l = new Log();
        l.setTitle(title);
        l.setType(logBusType.name());
        l.setRemoteAddr(JakartaServletUtil.getClientIP(request));
        l.setRequestUri(URLUtil.getPath(request.getRequestURI()));
        l.setMethod(request.getMethod());
        l.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        l.setParams(HttpUtil.toParams(request.getParameterMap()));
        l.setServiceId(serviceId);
        String name = SecurityContextHolder.getContext().getAuthentication().getName();
        l.setCreateBy(name);
        l.setUpdateBy(name);
        // 发送异步日志事件
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Object obj;

        try {
            obj = point.proceed();
        } catch (Exception e) {
            l.setException(e.getMessage());
            throw e;
        } finally {
            stopWatch.stop();
            l.setTime(stopWatch.getTotalTimeMillis());
            SpringContextHolder.publishEvent(new SysLogEvent(l));
        }

        return obj;
    }

}
